﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
// Added for GamePad support
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
/*needed for audio alerts*/
using System.Media;
/*socket communication*/
using System.Net;
using System.Net.Sockets;
/*synchronization*/
using System.Threading;
/*XML*/
using System.Xml;
using System.Xml.Serialization;
using System.Diagnostics;

namespace OCU
{
    public partial class Form1 : Form
    {
        enum sendStatus { Go, Stop };
        
        #region Constants

        
        #endregion

        #region Variables
        /// <summary>
        /// Used to define selected controller
        /// </summary>
        PlayerIndex playerIndex;

        /*timer variables*/
        DateTime startTime;
        int prevSecond;

        /*sensitivity*/
        int sensitivity = 3;

        /*update style*/
        Boolean continuousUpdate = true;

        /*send status*/
        int send_status = (int)sendStatus.Stop;

        /*motor config*/
        int motorMaxVal = 300;
        int motorCrawlVal = 50;

        /*maximum amount of time (ms) between sends when using update on change only mode*/
        int maxWait = 250;

        /*camera control*/
        bool invertY = false;

        /*UDP stuff*/
        Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        IPEndPoint sendEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.151"), 11000);
        int udpInPort = 11001;
        Boolean inPortChanged = false;
        static DateTime lastSend;

        /*lunabot states*/
        LunabotOutputState currentState = new LunabotOutputState();
        LunabotOutputState prevState = new LunabotOutputState();

        /*serializer components*/
        XmlSerializer serializer = new XmlSerializer(typeof(LunabotOutputState));
        MemoryStream output;

        /*locks*/
        static readonly object sendEndPointLocker = new object();
        static readonly object inPortLocker = new object();
        static readonly object sensitivityLocker = new object();
        static readonly object updateStyleLocker = new object();
        static readonly object sendStatusLocker = new object();
        static readonly object inPortChangeLocker = new object();
        static readonly object motorConfigLocker = new object();

        #endregion
        
        #region Constructor & Startup
        public Form1()
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            /*set input boxes according to variable values*/
            lock (sendEndPointLocker)
            {
                robotAddress.Text = sendEndPoint.Address.ToString();
                sendPort.Text = sendEndPoint.Port.ToString();
                udpOutgoingEndpointInUse.Text = sendEndPoint.ToString();
            }

            lock (inPortLocker)
            {
                receivePort.Text = udpInPort.ToString();
                receivePortInUse.Text = udpInPort.ToString();
            }

            intervalRate.Text = timerControllerUpdate.Interval.ToString();
            iRateInUse.Text = timerControllerUpdate.Interval.ToString() + " ms";

            lock (updateStyleLocker)
            {
                if (continuousUpdate)
                {
                    ContinuousRadioButton.Checked = true;
                    updateStyleInUse.Text = "Continuous";
                }
                else
                {
                    changeOnlyRadioButton.Checked = true;
                    updateStyleInUse.Text = "Change Only";
                }
            }

            lock (sensitivityLocker)
            {
                SensitivityList.Text = sensitivity.ToString();
                sensitivitySettingInUse.Text = sensitivity.ToString();
            }

            lock (motorConfigLocker)
            {
                crawlRate.Text = motorCrawlVal.ToString();
                motorCrawlInUse.Text = motorCrawlVal.ToString();
                motorMax.Text = motorMaxVal.ToString();
                motorMaxInUse.Text = motorMaxVal.ToString();
            }

            invertAxis.Checked = invertY;
            /*start controller & controller update timer*/
            playerIndex = PlayerIndex.One;
            timerControllerUpdate.Start();
            UDPReceiver.WorkerReportsProgress = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            UDPReceiver.RunWorkerAsync();
            cameraWorker.RunWorkerAsync();
        }
        #endregion

        #region controller
        private void timerControllerUpdate_Tick(object sender, EventArgs e)
        {
            try
            {
                /*update graphics*/
                controllerBox.Refresh();
                sensitivityFeedback.Refresh();

                /*retrieve gamepad state*/
                prevState = currentState;
                currentState = getOutputState();

                /*check status*/
                lock (sendStatusLocker)
                {
                    switch (send_status)
                    {
                        case (int)sendStatus.Go:
                            break;
                        case (int)sendStatus.Stop:
                            return;
                    }
                }

                lock (updateStyleLocker)
                {
                    if (!continuousUpdate && currentState.Equals(prevState))
                    {
                        /*check if it's been too long since the last send*/
                        TimeSpan wait = DateTime.Now - lastSend;
                        Debug.WriteLine(wait.Milliseconds.ToString());
                        if(wait.Milliseconds < maxWait)
                            return; /*state hasn't changed, no timeout issue - skip*/
                    }
                }
                output = new MemoryStream();
                /*assemble and send UDP packet*/
                serializer.Serialize(output, currentState);

                /*send packet*/
                lock (sendEndPointLocker)
                {
                    sendSocket.SendTo(output.ToArray(), sendEndPoint);
                }
                /*update time*/
                lastSend = DateTime.Now;

            }
            catch (Exception ex)
            {
                /*uh-oh*/
            }
        }

        private LunabotOutputState getOutputState()
        {
            LunabotOutputState outputState = new LunabotOutputState();
            if (GamePad.GetState(playerIndex).IsConnected)
            {
                GamePadState gamePadState = GamePad.GetState(playerIndex);
                /*motor values based on left analog stick and sensitivity setting...*/
                int x, y, crawl, max, sens, leftMotor, rightMotor;
                lock (motorConfigLocker)
                {
                    crawl = motorCrawlVal;
                    max = motorMaxVal;
                }
                lock (sensitivityLocker)
                {
                    sens = sensitivity;
                }
                /*check for crawl mode or normal control*/
                if (gamePadState.Buttons.LeftStick == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                {
                    leftMotor = crawl;
                    rightMotor = crawl;
                }
                else
                {
                    x = (Int32)(max * ((Math.Pow(Math.E, sens * gamePadState.ThumbSticks.Left.X)) - 1) / ((Math.Pow(Math.E, sens * gamePadState.ThumbSticks.Left.X)) + 1));
                    y = (Int32)(max * ((Math.Pow(Math.E, sens * gamePadState.ThumbSticks.Left.Y)) - 1) / ((Math.Pow(Math.E, sens * gamePadState.ThumbSticks.Left.Y)) + 1));

                    /*steering*/
                    if ((x > 0 && y > 0) || (x < 0 && y < 0)) /*forward/right and reverse/left*/
                    {
                        leftMotor = y;
                        rightMotor = y - x;
                    }
                    else if (x < 0 && y > 0 || (x > 0 && y < 0)) /*reverse/right and forward/left*/
                    {
                        leftMotor = y + x;
                        rightMotor = y;
                    }
                    else /*either x or y is zero*/
                    {
                        leftMotor = y + x;
                        rightMotor = y - x;
                    }
                }
                outputState.motorSpeedLeft = leftMotor;
                outputState.motorSpeedRight = rightMotor;

                /*check digging drive triggers*/
                if ((gamePadState.Triggers.Right > 0 && gamePadState.Triggers.Left > 0) || (gamePadState.Triggers.Right == 0 && gamePadState.Triggers.Left == 0))
                    outputState.diggingMechanism = 1500;
                else if (gamePadState.Triggers.Right > 0)
                    outputState.diggingMechanism = (Int32)Math.Round(1500 + gamePadState.Triggers.Right * 500);
                else if (gamePadState.Triggers.Left > 0)
                    outputState.diggingMechanism = (Int32)Math.Round(1500 + gamePadState.Triggers.Left * -500);

                /*check digging head buttons*/
                if ((gamePadState.Buttons.RightShoulder == Microsoft.Xna.Framework.Input.ButtonState.Pressed && gamePadState.Buttons.LeftShoulder == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    || (gamePadState.Buttons.RightShoulder == Microsoft.Xna.Framework.Input.ButtonState.Released && gamePadState.Buttons.LeftShoulder == Microsoft.Xna.Framework.Input.ButtonState.Released))
                    outputState.diggingHead = LunabotOutputState.ActionState.Off;
                else if (gamePadState.Buttons.RightShoulder == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    outputState.diggingHead = LunabotOutputState.ActionState.Down;
                else if (gamePadState.Buttons.LeftShoulder == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    outputState.diggingHead = LunabotOutputState.ActionState.Up;

                /*check collector bin buttons*/
                if ((gamePadState.Buttons.Y == Microsoft.Xna.Framework.Input.ButtonState.Pressed && gamePadState.Buttons.A == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    || (gamePadState.Buttons.Y == Microsoft.Xna.Framework.Input.ButtonState.Released && gamePadState.Buttons.A == Microsoft.Xna.Framework.Input.ButtonState.Released))
                    outputState.collectionBin = 1500;
                else if (gamePadState.Buttons.Y == Microsoft.Xna.Framework.Input.ButtonState.Pressed) /*dump bucket*/
                    outputState.collectionBin = 1000;
                else if (gamePadState.Buttons.A == Microsoft.Xna.Framework.Input.ButtonState.Pressed) /*return bucket*/
                    outputState.collectionBin = 2000;
            }
            else
            {
                //no controller connected! use keyboard
            }
            return outputState;
        }
        #endregion

        #region timer methods
        private void timerStart_Click(object sender, EventArgs e)
        {
            startTime = DateTime.Now;
            timerStart.Enabled = false;
            prevSecond = -1;
            timer.Start();
        }

        private void timerReset_Click(object sender, EventArgs e)
        {
            timer.Stop();
            timerDisplay.ForeColor = System.Drawing.Color.LawnGreen;
            timerDisplay.Text = "15:00";
            timerStart.Enabled = true;
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            /*calculate timer value*/
            TimeSpan elapsedTime = DateTime.Now - startTime;
            int seconds = (60 - elapsedTime.Seconds) % 60;
            int minutes = 15 - elapsedTime.Minutes;
            if (seconds > 0)
                minutes--;

            if (minutes < 0) return; //if timer has expired, do nothing.

            if (minutes < 5)
            {
                timerDisplay.ForeColor = System.Drawing.Color.Red;
                //beeping and text color
                //switch (minutes)
                //{
                //    /****Beep does not seem to work in some versions of windows...will have to find some other sound (can use our own .wav file if we want)
                //     * Will probably want to choose different beeping rates, which can be edited easily in this switch statment
                //     **** */
                //    case 2:
                //        //beep every 15 seconds
                //        if (seconds % 15 == 0 && seconds != prevSecond) SystemSounds.Beep.Play();
                //        break;
                //    case 1:
                //        //beep every 10 seconds
                //        if (seconds % 10 == 0 && seconds != prevSecond) SystemSounds.Beep.Play();
                //        break;
                //    case 0: //beep every 5 seconds
                //        if (seconds % 5 == 0 && seconds != prevSecond) SystemSounds.Beep.Play();
                //        break;
                //}

            }
            else if (minutes < 10)
                timerDisplay.ForeColor = System.Drawing.Color.Yellow;
            else
                timerDisplay.ForeColor = System.Drawing.Color.LawnGreen;

            /*update timer display*/
            timerDisplay.Text = String.Format("{0:00}:{1:00}", minutes, seconds);

            prevSecond = seconds;
        }
        #endregion

        #region input apply methods 
        private void sensitivityApplyButton_Click(object sender, EventArgs e)
        {
            lock (sensitivityLocker)
            {
                sensitivity = Int32.Parse(SensitivityList.Text);
            }
            sensitivitySettingInUse.Text = sensitivity.ToString();
        }

        private void applySend_Click(object sender, EventArgs e)
        {
            IPAddress tempAddress;
            int tempPort;
            try
            {
                tempAddress = IPAddress.Parse(robotAddress.Text);
                tempPort = Int32.Parse(sendPort.Text);

                /*verify that port number is valid*/
                if (tempPort < 0 || tempPort > 65535)
                {
                    MessageBox.Show("Invalid port number: must be between 0-65535");
                    return;
                }
                else
                {
                    lock (sendEndPointLocker)
                    {
                        sendEndPoint = new IPEndPoint(tempAddress, tempPort);
                        udpOutgoingEndpointInUse.Text = sendEndPoint.ToString();
                    }
                }
            }
            catch (Exception ex)
            {
                return;
            }
        }

        private void applyReceive_Click(object sender, EventArgs e)
        {
            int tempPort;
            try
            {
                tempPort = Int32.Parse(receivePort.Text);
                /*check for valid port*/
                if (tempPort < 0 || tempPort > 65535)
                {
                    MessageBox.Show("Invalid port number: must be between 0-65535");
                    return;
                }
                else //port is valid
                {
                    lock (inPortLocker)
                    {
                        udpInPort = tempPort;
                        receivePortInUse.Text = udpInPort.ToString();
                    }
                    lock (inPortChangeLocker)
                    {
                        inPortChanged = true;
                    }
                }
            }
            catch (Exception ex)
            {
                return;
            }
        }

        private void applyUpdateRate_Click(object sender, EventArgs e)
        {
            try
            {
                int interval = Int32.Parse(intervalRate.Text);
                if (interval <= 0 || interval > 1000) //allow delays between 1ms and 1 second
                    MessageBox.Show("Choose an interval between 1-1000 ms and try again.");
                else
                {
                    timerControllerUpdate.Interval = interval;
                    iRateInUse.Text = interval.ToString() + " ms";

                    lock (updateStyleLocker)
                    {
                        if (changeOnlyRadioButton.Checked == true)
                        {
                            continuousUpdate = false;
                            updateStyleInUse.Text = "Change Only";
                        }
                        else
                        {
                            continuousUpdate = true;
                            updateStyleInUse.Text = "Continuous";
                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }        

        private void sendStart_Click(object sender, EventArgs e)
        {
            lock (sendStatusLocker)
            {
                send_status = (int)sendStatus.Go;
            }

            udpOutgoingStatus.Text = "Active";
            udpOutgoingStatus.ForeColor = System.Drawing.Color.Green;
        }

        private void sendStop_Click(object sender, EventArgs e)
        {
            lock (sendStatusLocker)
            {
                send_status = (int)sendStatus.Stop;
            }
            
            udpOutgoingStatus.Text = "Inactive";
            udpOutgoingStatus.ForeColor = System.Drawing.Color.Red;

        }

        private void applyMotorConfig_Click(object sender, EventArgs e)
        {
            int max, crawl;
            try
            {
                max = Int32.Parse(motorMax.Text);
                if (max < 0 || max > 1000)
                {
                    MessageBox.Show("Maximum motor value magnitude must be between 0-1000");
                    return;
                }
                crawl = Int32.Parse(crawlRate.Text);
                if (crawl < 0 || crawl > max)
                {
                    MessageBox.Show("Crawl value must be positive and no greater than the max");
                    return;
                }
                lock (motorConfigLocker)
                {
                    motorMaxVal = max;
                    motorMaxInUse.Text = max.ToString();
                    motorCrawlVal = crawl;
                    motorCrawlInUse.Text = crawl.ToString();
                }
            }
            catch (Exception ex)
            {
            }
        }
        #endregion

        #region input validation methods
        private void robotAddress_Validating(object sender, CancelEventArgs e)
        {

        }

        private void sendPort_Validating(object sender, CancelEventArgs e)
        {

        }

        private void receivePort_Validating(object sender, CancelEventArgs e)
        {

        }

        private void intervalRate_Validating(object sender, CancelEventArgs e)
        {

        }

        private void crawlRate_Validating(object sender, CancelEventArgs e)
        {

        }

        private void motorMax_Validating(object sender, CancelEventArgs e)
        {

        }
        #endregion

        #region UDP receiving and GUI update
        private void UDPReceiver_DoWork(object sender, DoWorkEventArgs e)
        {
            UdpClient listener;
            IPEndPoint groupEP;

            lock (inPortLocker)
            {
                listener = new UdpClient(udpInPort);
                groupEP = new IPEndPoint(IPAddress.Any, udpInPort);
            }
            byte[] buffer;
            MemoryStream bufferStream;
            XmlSerializer deserializer = new XmlSerializer(typeof(LunabotHealthState));
            while (true)
            {
                try
                {
                      /*check if client/endpoint need to be set to a new port*/
                    lock (inPortChangeLocker)
                    {
                        if (inPortChanged)
                        {
                            lock (inPortLocker)
                            {
                                listener = new UdpClient(udpInPort);
                                groupEP = new IPEndPoint(IPAddress.Any, udpInPort);
                            }
                            /*reset inPortChanged so we don't bother with this next time*/
                            inPortChanged = false;
                        }
                    }
                    /*begin receiving!*/
                    buffer = listener.Receive(ref groupEP);
                    bufferStream = new MemoryStream(buffer);
                    /*deserialize*/
                    LunabotHealthState healthState = new LunabotHealthState();
                    healthState = (LunabotHealthState)deserializer.Deserialize(bufferStream);

                    ///*report progress*/
                    UDPReceiver.ReportProgress(0, healthState);

                }
                catch (Exception ex)
                {
                }
            }
        }

        private void UDPReceiver_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e == null)
                return;
            /*cast user state to health data structure*/
            try
            {
                LunabotHealthState state = e.UserState as LunabotHealthState;

                int electronicsBattery = (int)Math.Round(state.electronicsBatteryVoltage * 10);
                int excavationBattery = (int)Math.Round(state.excavationBatteryVoltage * 10);
                int driveBattery = (int)Math.Round(state.driveBatteryVoltage * 10);

                driveBatteryMeter.Value = (driveBattery > 370 ? 370 : driveBattery);
                excavationBatteryMeter.Value = (excavationBattery > 148 ? 148 : excavationBattery);
                electronicsBatteryMeter.Value = (electronicsBattery > 120 ? 120 : electronicsBattery);

                if (state.canDump)
                    dumpNotifyImage.BackgroundImage = (Image)new Bitmap(Path.Combine(Application.StartupPath, "no_error.bmp"));
                else
                    dumpNotifyImage.BackgroundImage = (Image)new Bitmap(Path.Combine(Application.StartupPath, "error.bmp"));

                leftMotorStatusLabel.Text = "Left Motor: " + state.OutputState.motorSpeedLeft.ToString();
                rightMotorStatusLabel.Text = "Right Motor: " + state.OutputState.motorSpeedRight.ToString();
                digMotorStatusLabel.Text = "Digging Motor: " + state.OutputState.diggingMechanism.ToString();
                digHeadStatusLabel.Text = "Digging Head: " + state.OutputState.diggingHead.ToString();
                collectionBinStatusLabel.Text = "Collection Bin Motor: " + state.OutputState.collectionBin.ToString();
            }
            catch (Exception ex)
            {
            }
        }
        #endregion

        #region PTZ Cam
        private void startVideoButton_Click(object sender, EventArgs e)
        {
            try
            {
                cameraWebPage.Navigate(Path.Combine(Application.StartupPath, "camera.html"));
            }
            catch (Exception ex)
            {
            }
        }

        private void stopVideoButton_Click(object sender, EventArgs e)
        {
            try
            {
                cameraWebPage.Navigate("about:blank");
            }
            catch (Exception ex)
            {
            }

        }

        private void invertAxis_CheckedChanged(object sender, EventArgs e)
        {
            invertY = invertAxis.Checked;
        }

        private void cameraWebPage_SizeChanged(object sender, EventArgs e)
        {
            autoZoom();
        }

        private void cameraWebPage_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            autoZoom();
        }

        private void autoZoom()
        {
            try
            {
                /*perform auto zoom*/
                int height = cameraWebPage.Size.Height;
                int width = cameraWebPage.Size.Width;

                /*find zoom ratios (subtract 10 to leave a border)*/
                int heightZoom = (int)(100.0 * (height - 10) / 240.0);
                int widthZoom = (int)(100.0 * (width - 10) / 352.0);

                /*zoom with lesser of the two values*/
                cameraWebPage.Zoom(Math.Min(heightZoom, widthZoom));
            }
            catch (Exception ex)
            {
            }
        }

        private void cameraWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            double pan, tilt, zoom;
            while (true)
            {

                try
                {
                    pan = 0;
                    tilt = 0;
                    zoom = 0;
                    if (GamePad.GetState(playerIndex).IsConnected)
                    {
                        GamePadState gamePadState = GamePad.GetState(playerIndex);
                        GamePadThumbSticks sticks = gamePadState.ThumbSticks;

                        /*check absolute buttons first*/
                        if (gamePadState.Buttons.RightStick == Microsoft.Xna.Framework.Input.ButtonState.Pressed
                            || gamePadState.DPad.Up == Microsoft.Xna.Framework.Input.ButtonState.Pressed
                            || gamePadState.DPad.Down == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                        {
                            string req = "http://192.168.1.152//axis-cgi/com/ptz.cgi?";

                            if (gamePadState.Buttons.RightStick == Microsoft.Xna.Framework.Input.ButtonState.Pressed) /*no zoom*/
                                req += "&zoom=0";
                            if (gamePadState.DPad.Up == Microsoft.Xna.Framework.Input.ButtonState.Pressed) /*look forward*/
                                req += "&tilt=-50&pan=92";
                            else if (gamePadState.DPad.Down == Microsoft.Xna.Framework.Input.ButtonState.Pressed) /*down backward*/
                                req += "&tilt=-27&pan=-84";

                            HttpWebRequest request = (HttpWebRequest)
                                WebRequest.Create(req);
                            // execute the request
                            HttpWebResponse response = (HttpWebResponse)
                            request.GetResponse();
                            response.Close();
                        }
                        else /*relative movement*/
                        {
                            /*set pan/tilt by stick*/
                            pan = Math.Round(5 * sticks.Right.X, 2);
                            tilt = Math.Round(5 * sticks.Right.Y * (invertY ? -1 : 1), 2);
                            /*zoom*/
                            if (gamePadState.DPad.Left == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                                zoom = -50;
                            else if (gamePadState.DPad.Right == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                                zoom = 50;

                            HttpWebRequest request = (HttpWebRequest)
                                WebRequest.Create("http://192.168.1.152//axis-cgi/com/ptz.cgi?" + "rpan=" + pan.ToString("F2") + "&rtilt=" + tilt.ToString("F2") + "&rzoom=" + zoom.ToString("F2"));
                            // execute the request
                            HttpWebResponse response = (HttpWebResponse)
                            request.GetResponse();
                            response.Close();
                        }
                    }
                    else /*keyboard control*/
                    {

                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }
        }
        #endregion        

        #region paint methods
        private void controllerBox_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            GamePadState gamePadState = GamePad.GetState(playerIndex);
            /*analog sticks*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.Buttons.LeftStick ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 25 + gamePadState.ThumbSticks.Left.X * 25,
                135 + gamePadState.ThumbSticks.Left.Y * -25, 70, 70); /*left stick*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.Buttons.RightStick ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 225 + gamePadState.ThumbSticks.Right.X * 25,
                225 + gamePadState.ThumbSticks.Right.Y * -25, 70, 70); /*right stick*/

            /*center crosshairs*/
            g.DrawLine(new Pen(new SolidBrush(System.Drawing.Color.White), 2), 255, 260, 265, 260);
            g.DrawLine(new Pen(new SolidBrush(System.Drawing.Color.White), 2), 260, 255, 260, 265);
            g.DrawLine(new Pen(new SolidBrush(System.Drawing.Color.White), 2), 55, 170, 65, 170);
            g.DrawLine(new Pen(new SolidBrush(System.Drawing.Color.White), 2), 60, 165, 60, 175);

            /*quad buttons*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb((gamePadState.Buttons.Y ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed) ? 255 : 100, 238, 131, 14)), 325, 115, 30, 30); /*Y*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb((gamePadState.Buttons.A ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed) ? 255 : 100, 136, 167, 107)), 325, 195, 30, 30); /*A*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb((gamePadState.Buttons.X ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed) ? 255 : 100, 48, 81, 158)), 290, 155, 30, 30); /*X*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb((gamePadState.Buttons.B ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed) ? 255 : 100, 185, 43, 39)), 360, 155, 30, 30); /*B*/

            /*d pad*/
            Pen pen = new Pen(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.DPad.Left ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 10);
            pen.EndCap = LineCap.ArrowAnchor;
            g.DrawLine(pen, 105, 260, 85, 260); /*left*/
            pen = new Pen(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.DPad.Right ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 10);
            pen.EndCap = LineCap.ArrowAnchor;
            g.DrawLine(pen, 135, 260, 155, 260); /*right*/
            pen = new Pen(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.DPad.Up ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 10);
            pen.EndCap = LineCap.ArrowAnchor;
            g.DrawLine(pen, 120, 245, 120, 225); /*up*/
            pen = new Pen(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.DPad.Down ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 10);
            pen.EndCap = LineCap.ArrowAnchor;
            g.DrawLine(pen, 120, 275, 120, 295); /*down*/


            /*left bumper*/
            System.Drawing.Rectangle rect = new System.Drawing.Rectangle(25, 80, 70, 25);
            System.Drawing.Rectangle roundedRectangle = System.Drawing.Rectangle.Round(rect);
            if (gamePadState.Buttons.LeftShoulder == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), roundedRectangle);
            else
                g.DrawRectangle(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), 3), roundedRectangle);

            /*right bumper*/
            rect = new System.Drawing.Rectangle(305, 80, 70, 25);
            roundedRectangle = System.Drawing.Rectangle.Round(rect);
            if (gamePadState.Buttons.RightShoulder == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), roundedRectangle);
            else
                g.DrawRectangle(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), 3), roundedRectangle);

            /*triggers*/
            /*left*/
            rect = new System.Drawing.Rectangle(48, 0, 25, 70);
            roundedRectangle = System.Drawing.Rectangle.Round(rect);
            g.DrawRectangle(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 180)), 3), roundedRectangle);
            rect = new System.Drawing.Rectangle(48, 0, 25, (Int32)(70 * gamePadState.Triggers.Left));
            g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), rect);
            /*right*/
            rect = new System.Drawing.Rectangle(328, 0, 25, 70);
            roundedRectangle = System.Drawing.Rectangle.Round(rect);
            g.DrawRectangle(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 180)), 3), roundedRectangle);
            rect = new System.Drawing.Rectangle(328, 0, 25, (Int32)(70 * gamePadState.Triggers.Right));
            g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), rect);


            /*back*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.Buttons.Back ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 120, 155, 35, 25);
            /*start*/
            g.FillEllipse(new SolidBrush(System.Drawing.Color.FromArgb(gamePadState.Buttons.Start ==
                Microsoft.Xna.Framework.Input.ButtonState.Pressed ? 255 : 100, 65, 85, 85)), 230, 155, 35, 25);
        }

        private void sensitivityFeedback_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            GamePadState gamePadState = GamePad.GetState(playerIndex);

            int x, y;
            double xin = gamePadState.ThumbSticks.Left.X;
            double yin = gamePadState.ThumbSticks.Left.Y;

            /*fill boxes*/
            x = (Int32)(100 * ((Math.Pow(Math.E, Int32.Parse(SensitivityList.Text) * gamePadState.ThumbSticks.Left.X)) - 1) /
                ((Math.Pow(Math.E, Int32.Parse(SensitivityList.Text) * gamePadState.ThumbSticks.Left.X)) + 1));
            y = -1 * (Int32)(100 * ((Math.Pow(Math.E, Int32.Parse(SensitivityList.Text) * gamePadState.ThumbSticks.Left.Y)) - 1) /
                ((Math.Pow(Math.E, Int32.Parse(SensitivityList.Text) * gamePadState.ThumbSticks.Left.Y)) + 1));

            if (x >= 0)
                g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), 125, 190, 75 * x / 100, 40);
            else
                g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), 125 - 75 * -x / 100, 190, 75 * -x / 100, 40);
            if (y >= 0)
                g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), 105, 95, 40, 75 * y / 100);
            else
                g.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(255, 0, 191, 255)), 105, 95 - 75 * -y / 100, 40, 75 * -y / 100);

            /*boundary boxes*/
            g.DrawRectangle(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 65, 85, 85)), 3), 105, 20, 40, 150);
            g.DrawLine(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 65, 85, 85)), 1), 105, 95, 145, 95);
            g.DrawRectangle(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 65, 85, 85)), 3), 50, 190, 150, 40);
            g.DrawLine(new Pen(new SolidBrush(System.Drawing.Color.FromArgb(255, 65, 85, 85)), 1), 125, 190, 125, 230);
        }



        private void proximityPanel_Paint(object sender, PaintEventArgs e)
        {

        }
        #endregion  
       
    }
}

